home *** CD-ROM | disk | FTP | other *** search
/ Internet Standards / CD1.mdf / winsock / hacker / 93-11 / 000003_paul@atlas.dev.abccomp.oz.au_Tue Nov 23 07:45:44 1993.msg < prev    next >
Internet Message Format  |  1993-11-29  |  12KB

  1. Received: from usage.csd.unsw.OZ.AU by SunSITE.Unc.EDU (5.65c+IDA/FvK-1.06) with SMTP
  2.           id AA23361; Mon, 22 Nov 1993 22:40:56 -0500
  3. Received: by usage.csd.unsw.OZ.AU id AA04547
  4.   (5.65c/IDA-1.4.4 for winsock-hackers%sunsite.unc.edu); Tue, 23 Nov 1993 14:40:59 +1100
  5. Received: by atlas (4.1/1.35)
  6.     id AA22280; Tue, 23 Nov 93 12:45:44 EST
  7. Message-Id: <9311230145.AA22280@atlas>
  8. From: paul@atlas.abccomp.oz.au
  9. Date: Tue, 23 Nov 1993 12:45:44 -0500
  10. X-Mailer: Mail User's Shell (7.2.2 4/12/91)
  11. To: winsock-hackers@sunsite.unc.edu
  12. Subject: accepting new connections in the presence of aborted ones.
  13.  
  14. I'm running into problems with a WSAT script, that seems to be assuming
  15. different behaviour to my assumptions. Please imagine these two machines
  16. execute the following pseudo-calls in time order increasing down the list - 
  17. calls side-by-side are synchronisation points:
  18.  
  19.         Machine 1                               Machine 2
  20.         s=socket                                s = socket
  21.         bind(s, cli_addr)                       bind(s, servaddr)
  22.                         listen(s,5)
  23.     connect(s, servaddr)            s2=accept(s)
  24.         { data transfer  - after a while,
  25.         { connection is reset for some reason }
  26.         { calls on both side return WSAECONNRESET/WSAECONNABORTED }
  27.     closesocket(s)
  28.     s2 = socket
  29.     bind(s2, cli_addr)
  30.     connect(s2, srv_addr)...(1)
  31.  
  32.                         closesocket(s2)
  33.  
  34.     Because the connection was reset, Machine 1 can bind() immediately
  35. to the same source address/port it had before, and tries to connect to the
  36. same server address/port as before. Because Machine 2 has not yet closed the
  37. socket, the incoming SYN matches the aborted connection. Should machine
  38. 2 fail the connection attempt, returnig RST, or create the new connection
  39. in the listening queue? I've always assuemd that an incoming segment which
  40. exactly matches both addresses and ports is associated with an existing
  41. connection if possible and a listening socket if not. At least one
  42. WSAT script seems to assume multiple times that the second connect()
  43. in the sequence above should succeed.
  44.  
  45.     Any thoughts from the protocol and BSD experts out there?
  46.  
  47. -- 
  48. Paul Brooks              |paul@abccomp.oz.au       |Emerging Standard:
  49. TurboSoft Pty Ltd        |pwb@newt.phys.unsw.edu.au|  one that has not yet
  50. 579 Harris St., Ultimo   |                         |  been superseded.
  51. Sydney Australia 2007    |ph: +61 2 281 3155       |  
  52. From paul@atlas.dev.abccomp.oz.au Tue Nov 23 07:26:00 1993
  53. Received: from usage.csd.unsw.OZ.AU by SunSITE.Unc.EDU (5.65c+IDA/FvK-1.06) with SMTP
  54.           id AA23395; Mon, 22 Nov 1993 22:41:19 -0500
  55. Received: by usage.csd.unsw.OZ.AU id AA04551
  56.   (5.65c/IDA-1.4.4 for winsock-hackers%sunsite.unc.edu); Tue, 23 Nov 1993 14:41:00 +1100
  57. Received: by atlas (4.1/1.35)
  58.     id AA22259; Tue, 23 Nov 93 12:26:00 EST
  59. Message-Id: <9311230126.AA22259@atlas>
  60. From: paul@atlas.abccomp.oz.au
  61. Date: Tue, 23 Nov 1993 12:26:00 -0500
  62. X-Mailer: Mail User's Shell (7.2.2 4/12/91)
  63. To: rcq@ftp.com, Multiple recipients of list <winsock-hackers@sunsite.unc.edu>
  64. Subject: Re: non-blocking lingering close
  65.  
  66. Thus expounded Bob Quinn on Nov 22, 9:15am:
  67. /--------------------
  68. |Hello Paul!
  69. |
  70. |>  I've been looking at using non-blocking calls, but emulating the behaviour
  71. |>  of a blocking close, and have determined there is no real way to
  72. |>  do so given the 1.1 interface spec.   A "blocking graceful close" is when
  73. |>  closesocket is called on a socket with a non-zero linger time, and it
  74. |>  should block, waiting for all the buffered outgoing data to be sent and
  75. |>  acknowledged before returning.
  76. |
  77. |Hmm, I think your premise needs further examination. :-)
  78. |To restate what I believe you are saying, you don't see any
  79. |way to avoid the possibility of closesocket() blocking.  Is
  80. |that correct?
  81.  
  82. Not entirely. I'm fully aware of the semantics on blocking, non-blocking and
  83. hard closes and the various combinations of linger settings.
  84. What I want to do is emulate the semantics of a lingering blocking graceful
  85. closesocket(), without actually blocking inside the implementation. I want
  86. to trigger the sending of the FIN in a non-blocking manner, then periodically
  87. check for when the connection has been fully gracefully closed, without
  88. causing the underlying implementation to block at any time.
  89.  
  90.  
  91. |I don't see any problem in the specification.  It's not prominent,
  92. |but page 12 of the spec does say closesocket() "only blocks if
  93. |SO_LINGER is set."  So by default, closesocket() should return
  94. |immediately and a graceful close should occur in the background.
  95.  
  96. Thats right, but then the resourses attache to that socket are not free'ed
  97. for some arbitrary time. In particular, its not possible to bind a socket
  98. to the same address/port immediately after this form of "background"
  99. closesocket without setting SO_REUSEADDR, as there is no way to tell when
  100. the connection has been closed, or even if the FIN has reached the
  101. remote host yet or not.
  102.     I want to be able to do:
  103.         closesocket_equivalent(s1)
  104.         s2=socket()
  105.         bind(s2,same_port_as_s1),
  106. WITHOUT using the blocking closesocket() by setting a struct linger to
  107. {1,something != 0}.
  108.  
  109. |>          The problem is that there is currently no way to determine if there
  110. |>  is still buffered data waiting to be written. Ioctlsocket() has the FIONREAD
  111. |>  parameter, to return an indication of data waiting to be read, but there is
  112. |>  no corresponding FIONWRITE parameter to determine if buffered data is still
  113. |>  waiting to be sent to the remote host, or has not been acknowledged.
  114. |>  
  115. |>          What are people's thoughts on emulating a lingering close, and whether
  116. |>  a new ioctlsocket() parameter could be defined for version 2.0.
  117. |
  118. |Not a good idea.  Our stack, for one, does not have a problem with
  119. |closes (blocking or not), but we *would* have a problem providing
  120. |ioctlsocket() FIONWRITE.  It's a violation of the API, since it
  121. |reaches into the stack and (in effect) tells you what TCP data has
  122. |not been acknowledged yet.  It begs for abuse.
  123.  
  124. "violation of the API"? APIs are defined to be what is found to be useful,
  125. and/or in this case largely compatible with BSD code. APIs aren't violated, 
  126. they are defined.
  127.  
  128. How does knowing how long the retransmission buffer is currently beg for abuse?
  129. How is this more abuse than being able to find out how many bytes are waiting
  130. to be read, before the recv() call? Please clarify your thoughts on this
  131. "abuse.". I thought proposing something like FIONWRITE was pleasing, if only on
  132. the grounds of symmetry!.
  133.  
  134. |If you want to avoid a blocking close, and you don't trust the
  135. |default non-blocking close, there is another option for you.  You
  136. |can do a shutdown() how==1, which sends a TCP <FIN> *AFTER* all
  137. |the buffered data is sent and acknowledged (in effect a <FIN> says
  138. |"I'm done sending data").  Then you should do recv's (non-blocking
  139. |and/or with the MSG_PEEK flag set).  When recv() returns 0 the
  140. |graceful close is complete, and it's safe to call closesocket().
  141.  
  142. Well, if recv() returns anything else except 0 or WSAEWOULDBLOCK the connection
  143. has to be reset anyway, just like it does now if closesocket() is called
  144. and the receive buffer still contains data.
  145.  
  146. Your proposal doesn't work in general, because the outgoing and incoming data
  147. streams are essentially independent. Its quite posible for the remote end
  148. to close its end, sending me a FIN, before it has read and acknowledged all
  149. the outgoing data in my buffer. Recv() returning zero doesn't tell me diddly
  150. about whether it has received all my data or not - you are assuming the only
  151. reason it would close is because it has received my FIN, which is not a valid
  152. assumption.
  153.  
  154. Do people bother with TIMEWAIT state, and disallowing bind()s for the port
  155. during TIMEWAIT?
  156.  
  157. Am I correct that a closesocket() with linger set on (for a long time)
  158. should block until the socket exits TIMEWAIT (if it is the first
  159. FIN sender)?
  160.  
  161. I decided to use a non-blocking graceful closesocket, let the socket be closed
  162. in the background, and loosely loop trying to bind a new socket to the
  163. same address until it succeeds. I'm not convinved all the error codes and
  164. conditions are covered though.
  165.  
  166. Anybody else with a solution?
  167.  
  168.  
  169. -- 
  170. Paul Brooks              |paul@abccomp.oz.au       |Emerging Standard:
  171. TurboSoft Pty Ltd        |pwb@newt.phys.unsw.edu.au|  one that has not yet
  172. 579 Harris St., Ultimo   |                         |  been superseded.
  173. Sydney Australia 2007    |ph: +61 2 281 3155       |  
  174. From rcq@ftp.com Tue Nov 23 07:23:21 1993
  175. Received: from ftp.com by SunSITE.Unc.EDU (5.65c+IDA/FvK-1.06) with SMTP
  176.           id AB23261; Tue, 23 Nov 1993 13:32:23 -0500
  177. Received: from rcq.oysters.ftp.com by ftp.com via PCMAIL with DMSP
  178.     id AA27251; Tue, 23 Nov 93 12:23:21 -0500
  179. Date: Tue, 23 Nov 93 12:23:21 -0500
  180. Message-Id: <9311231723.AA27251@ftp.com>
  181. To: paul@atlas.abccomp.oz.au
  182. Subject: Re: non-blocking lingering close
  183. From: rcq@ftp.com  (Bob Quinn)
  184. Reply-To: rcq@ftp.com
  185. Cc: Multiple recipients of list <winsock-hackers@sunsite.unc.edu>
  186. Sender: rcq@ftp.com
  187. Repository: babyoil.ftp.com
  188. Originating-Client: oysters.ftp.com
  189.  
  190. Hi Paul!
  191.  
  192. >  "violation of the API"? APIs are defined to be what is found to be useful,
  193. >  and/or in this case largely compatible with BSD code. APIs aren't violated, 
  194. >  they are defined.
  195.  
  196. One of the great advantages of the Windows Sockets API is that
  197. it hides low-level details.  APIs are indeed defined to be useful,
  198. but simplicity has great benefits.  Exposing low-level details
  199. complicates an API.  If its unnecessary, it's a violation.
  200.  
  201. >  How does knowing how long the retransmission buffer is currently beg for abuse?
  202. >  How is this more abuse than being able to find out how many bytes are waiting
  203. >  to be read, before the recv() call? Please clarify your thoughts on this
  204. >  "abuse.".
  205.  
  206. Detecting incoming data with FIONREAD is very different than
  207. detecting incoming acknowledgments with FIONWRITE.  Application
  208. developers would get a false sense of security knowing what data
  209. has been acknowledged, assuming that is the (only) data received
  210. by the other end.  If the connection fails, the sender may not
  211. see an acknowledgment for data the other end received.
  212.  
  213. >  Your proposal doesn't work in general, because the outgoing and incoming data
  214. >  streams are essentially independent. Its quite posible for the remote end
  215. >  to close its end, sending me a FIN, before it has read and acknowledged all
  216. >  the outgoing data in my buffer.
  217.  
  218. One side initiates the close of a TCP socket, not both.  If you
  219. have called shutdown(how=1), it's valid to expect recv()=0 to
  220. indicate the completion of a graceful close.  Otherwise you have
  221. a seriously broken client/server pair.
  222.  
  223. >  Do people bother with TIMEWAIT state, and disallowing bind()s for the port
  224. >  during TIMEWAIT?
  225.  
  226. Yes.  :)
  227.  
  228. >  Am I correct that a closesocket() with linger set on (for a long time)
  229. >  should block until the socket exits TIMEWAIT (if it is the first
  230. >  FIN sender)?
  231.  
  232. No.  And it doesn't matter what the timeout length is.  After 
  233. initiating the close, a blocking closesocket() returns immediately 
  234. after it receives the TCP <ACK><FIN>.  In other words, closesocket() 
  235. returns at the point the TCP connection enters the TIMEWAIT state.
  236.  
  237. The socket is invalid after the return from closesocket().  But if 
  238. it just completed a graceful close (that it initiated), the TCP 
  239. connection still has some life to it.  It can send another <ACK> 
  240. if the other side missed the first one and sends another <FIN>.  
  241. The port used cannot be bound by another socket until this TIMEWAIT 
  242. state expires.
  243.  
  244. >  I decided to use a non-blocking graceful closesocket, let the socket be closed
  245. >  in the background, and loosely loop trying to bind a new socket to the
  246. >  same address until it succeeds. I'm not convinved all the error codes and
  247. >  conditions are covered though.
  248.  
  249. That is a valid strategy, too.
  250.  
  251. Regards,
  252. --
  253.  Bob Quinn                                             rcq@ftp.com
  254.  FTP Software, Inc.                                No. Andover, MA